import type { DirectiveBinding, Directive } from 'vue'
// import type { Directive } from "vue";
// import type { DirectiveBinding, ObjectDirective } from 'vue'

// type DocumentHandler = <T extends MouseEvent>(e:T) => void
// interface ListProps {
//   documentHandler?: DocumentHandler
// }

/**
 * const myDirective = {
  // 在绑定元素的 attribute 前 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
   // 下面会介绍各个参数的细节
   },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
 }
 *
*/

// 如果有返回值 返回:DocumentHandler
const debounce: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    let timer = 0 as any
    el.addEventListener('click', () => {
      if (timer) {
        clearTimeout(timer)
      }
      timer = setTimeout(() => {
        binding.value()
      }, 1000)
    })
  }
}

// 应该是一开始就要监听 鼠标在区域内还是在区域外
// 问题1: 这个el, 是全局的吗  所以这个el不是全局, 只是传进来的, 添加了一个方法
// 点击dom外该dom隐藏的自定义指令
/**
 * 思路: 开启时就给我们的el挂载点击事件,
 * 然后我们点击时, 该事件会获取到我们点击到的dom
 * event是哪里来的? 每一个dom点击都会有这个属性, 不管你在哪点击
 * 然后根据event来比较两个dom是否相等或者包含
 * 如果发现不相等并且也不包含的话, 点击到区域外了
 * 接下来将传进来的函数调用, 卸载该dom的时候也将点击事件移除
 *
 * 看看有几个生命周期函数
 * 这里的el就是绑定的元素, 和点击的e.target比较是否相等就能判断是否在里面
 * binding: 调用自定义指令绑定的方法
 */
const hideDom: Directive = {
  mounted(el, binding: DirectiveBinding) {
    // 在元素插入到DOM时绑定事件
    // el.clickOutsideEvent 注意这里是在给el上添加一个函数, el本身没有这个函数
    el.clickOutsideEvent = function (event: Event) {
      // 判断点击事件是否发生在绑定的元素之外
      /**
       * 这里比较模糊的还是这里的event.target
       *  这里的el, 是挂载dom的el 然后这里的event.target， 是我们鼠标点击的el
       * 这样的话如果el和event.target相等的话， 就说明我们在该挂载自定义指令上的dom进行操作
       * 如果不相等， 并且el中不包含event.target的话， 就表示我们已经点击到外面去了
       * 点击到外面去了的话, 就要调用value, 传进来的方法
       * 当点击到外面去时, 最好将该dom销毁, 不然不好将事件移除
       */
      if (!(el === event.target || (el as Element).contains(event.target as Node))) {
        // 如果是, 调用绑定的方法
        // 自定义指令绑定方法不奇怪
        binding.value()
      }
    }
    // 开启点击事件 当该dom挂载时将会一直监听事件
    document.addEventListener('click', el.clickOutsideEvent)
  },
  unmounted(el) {
    // 将元素从dom中移除时解绑事件
    document.removeEventListener('click', el.clickOutsideEvent)
  }
}
export default { debounce, hideDom }
